package main;

import java.util.ArrayList;

/**
 * Function followed by a constant decleration followed by addr or constant
 *	lit 0,a: load constant a
 *	lod l,a: load variable l,a
 *	sto l,a: store variable l,a
 *	cal l,a: call void a at level l
 *	inc 0,a: increment t-register by a
 *	jmp 0,a: jump to a
 *	jpc 0,a: jump conditional to a
 *  add 0,a: add a to top of stack
 *  div 0,a: divide a to top of stack
 *  sub 0,a: subtract a from top of stack
 *  mul 0,a: multiply a by top of stack
 *  neg 0,a: make variable negative
 *  lte 0,a: a less than or equal to number on top of stack
 *  gte 0,a: a greater than or equal to number on top of stack
 *  grt 0,a: a greater than number on top of stack
 *  lst 0,a: a less than number on top of stack
 *  all operation can use constants by: ex. add 1,67: adds 67 to top of stack
 */

public class Segment {
	// Instruction types
	public static final int lit = 0;
	public static final int opr = 1;
	public static final int lod = 2;
	public static final int sto = 3;
	public static final int cal = 4;
	public static final int inct = 5;
	public static final int jmp = 6;
	public static final int jpc = 7;
	public static final int opReturn = 8;
	public static final int opUnaryMinus = 9;
	public static final int opPlus = 10;
	public static final int opMinus = 11;
	public static final int opTimes = 12;
	public static final int opDiv = 13;
	public static final int opOdd = 14;
	public static final int opEqual = 15;
	public static final int opNotEqual = 16;
	public static final int opLess = 17;
	public static final int opGreaterEqual = 18;
	public static final int opGreater = 19;
	public static final int opLessEqual = 20;
	public static final int opWrite = 21;
	public static final int opNewLine = 22;
	public static final int opRead = 23;
	public static final int end = 24;

	public ArrayList<Instr> code;
	public static String mnemonic[];

	//numbner of instruction and maximum allowable instructions
	int cx = 0;
	static int cxmax = 500;

	public Segment() {
		code = new ArrayList<Instr>();
		mnemonic = new String[end + 1];
		mnemonic[lit] = "lit";
		mnemonic[opr] = "opr";
		mnemonic[lod] = "lod";          mnemonic[sto] = "sto";
		mnemonic[cal] = "cal";
		mnemonic[inct] = "int";
		mnemonic[jmp] = "jmp";
		mnemonic[jpc] = "jpc";
		mnemonic[opReturn] = "ret";
		mnemonic[opUnaryMinus] = "neg";
		mnemonic[opPlus] = "add";
		mnemonic[opMinus] = "sub";
		mnemonic[opTimes] = "mul";
		mnemonic[opDiv] = "div";
		mnemonic[opOdd] = "odd";
		mnemonic[opEqual] = "eql";
		mnemonic[opNotEqual] = "neq";
		mnemonic[opLess] = "lst";
		mnemonic[opGreaterEqual] = "gte";
		mnemonic[opGreater] = "grt";
		mnemonic[opLessEqual] = "lte";
		mnemonic[opWrite] = "wtl";
		mnemonic[opNewLine] = "nwl";
		mnemonic[opRead] = "rdl";
		mnemonic[end] = "end";
	}

	/**
	 * generates a code segment
	 * @param fct the op code for the specific function
	 * @param constant is constant or variable
	 * @param addr address or constant
	 */
	public void gen (int fct, int constant, int addr) {
		if (cx > cxmax) {
			System.out.println("Program too long");
			System.exit(0);
		} else {
			code.add(new Instr(fct, constant, addr));
		}
		cx++;
	}

	/**
	 * Sets the address field on the particular address
	 * @param instradr Address to set field on
	 * @param adrVal value to add
	 */
	public void setAddrField(int instradr, int adrVal) {
		try {
			Instr i = (Instr) code.get(instradr);
			i.address = adrVal;
		} catch (IndexOutOfBoundsException e) {
		}
	}

	/**
	 * The next available address
	 * @return The next address that is unused
	 */
	public int nextInstrAdr() {
		// Current code position
		return code.size();
	}

	/**
	 * Lists the assembly code
	 */
	public void listcode() { // list code generated for this block
		Machine.out.println("ASSEMBLY CODE");
		for (int i = 0; i<cx; i++) {
			Machine.out.println ("Line" + i + ":\t" + mnemonic[code.get(i).function] + "\t" + code.get(i).constant + "\t" +code.get(i).address);
		} // end listcode
//		System.out.println("\n");
		Machine.out.println("\n");
	}
}
